package report

import (
	"fmt"

	"github.com/shirou/gopsutil/v3/net"
	"gopkg.in/yaml.v2"
)

type NetworkInfo struct {
	Index        int      `json:"index" yaml:"index"` // e.g., 1
	MTU          int      `json:"mtu" yaml:"mtu"`     // e.g., 1500
	Name         string   `json:"name" yaml:"name"`   // e.g., "en0", "lo0", "eth0.100"
	HardwareAddr string   `json:"hardwareAddr" yaml:"hardwareAddr"`
	Flags        []string `json:"flags" yaml:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast
	Addrs        []string `json:"addrs" yaml:"addrs"`

	BytesSent   uint64 `json:"bytesSent" yaml:"bytesSent"`     // number of bytes sent
	BytesRecv   uint64 `json:"bytesRecv" yaml:"bytesRecv"`     // number of bytes received
	PacketsSent uint64 `json:"packetsSent" yaml:"packetsSent"` // number of packets sent
	PacketsRecv uint64 `json:"packetsRecv" yaml:"packetsRecv"` // number of packets received
	Errin       uint64 `json:"errin" yaml:"errin"`             // total number of errors while receiving
	Errout      uint64 `json:"errout" yaml:"errout"`           // total number of errors while sending
	Dropin      uint64 `json:"dropin" yaml:"dropin"`           // total number of incoming packets which were dropped
	Dropout     uint64 `json:"dropout" yaml:"dropout"`         // total number of outgoing packets which were dropped
	Fifoin      uint64 `json:"fifoin" yaml:"fifoin"`           // total number of FIFO buffers errors while receiving
	Fifoout     uint64 `json:"fifoout" yaml:"fifoout"`         // total number of FIFO buffers errors while sending

}

func (n *NetworkInfo) Show() {
	out, err := yaml.Marshal(n)
	if err != nil {
		return
	}

	fmt.Printf("network : %v\n", string(out))
}

func FetchNetworkInfo() []NetworkInfo {

	var networkInfoList []NetworkInfo

	// Interfaces
	interfaces, err := net.Interfaces()
	if err != nil {
		return nil
	}

	interfacesIOCounters, err2 := net.IOCounters(true)
	if err2 != nil {
		return nil
	}

	for _, iface := range interfaces {
		addrs := make([]string, 0)
		for _, v := range iface.Addrs {
			addrs = append(addrs, v.String())
		}
		networkInfoList = append(networkInfoList, NetworkInfo{
			Index:        iface.Index,
			MTU:          iface.MTU,
			Name:         iface.Name,
			HardwareAddr: iface.HardwareAddr,
			Flags:        iface.Flags,
			Addrs:        addrs,
		})

		for i, ifaceIO := range interfacesIOCounters {
			if ifaceIO.Name == iface.Name {
				networkInfoList[i].BytesSent = ifaceIO.BytesSent
				networkInfoList[i].BytesRecv = ifaceIO.BytesRecv
				networkInfoList[i].PacketsSent = ifaceIO.PacketsSent
				networkInfoList[i].PacketsRecv = ifaceIO.PacketsRecv
				networkInfoList[i].Errin = ifaceIO.Errin
				networkInfoList[i].Errout = ifaceIO.Errout
				networkInfoList[i].Dropin = ifaceIO.Dropin
				networkInfoList[i].Dropout = ifaceIO.Dropout
				networkInfoList[i].Fifoin = ifaceIO.Fifoin
				networkInfoList[i].Fifoout = ifaceIO.Fifoout
				break
			}
		}
	}

	return networkInfoList
}

func ShowNetworkSummary(networkInfoList []NetworkInfo) {

	for _, networkInfo := range networkInfoList {
		networkInfo.Show()
	}
}

func FetchIpAddresses() []string {
	var ipAddresses []string
	interfaces, err := net.Interfaces()
	if err != nil {
		return nil
	}
	for _, iface := range interfaces {
		for _, v := range iface.Addrs {
			ipAddresses = append(ipAddresses, v.Addr)
		}
	}
	return ipAddresses
}
